<?php

namespace Hx;

/**
 * 路由类
 * Class Router
 * @package Hx
 */
class Router {

    /**
     * 路由参数
     * @var array
     */
    private static $param = array();

    /**
     * 获取路由参数
     * @param bool|int $index 索引值或true
     * @return array|string
     */
    public static function getParam($index = true) {
        return $index === true ? self::$param : self::$param[$index];
    }

    /**
     * 扩展名
     * @var string
     */
    private static $ext = 'html';

    /**
     * 获取扩展名
     * @return string
     */
    public static function getExt() {
        return self::$ext;
    }

    /**
     * 请求方式
     * @var string
     */
    private static $method = 'GET';

    /**
     * 路由规则数据
     * @var array
     */
    private static $ruleData = array();

    /**
     * 设置规则
     * @param string $method
     * @param string|array $url
     * @param array|\Closure $callback
     */
    private static function setRule($method, $url, $callback) {
        #多条url同一条规则
        if (is_array($url)) {
            foreach ($url as $u) {
                self::setRule($method, $u, $callback);
            }
            return;
        }
        #处理后缀名
        $ext = pathinfo($url, PATHINFO_EXTENSION);
        if ($ext) {
            $url = str_replace('.' . $ext, '', $url);
            $rule['ext'] = $ext;
        } else {
            $rule['ext'] = 'html';
        }
        #处理其他参数
        $rule['param'] = array_values(array_filter(explode('/', $url)));
        $rule['method'] = strtoupper($method);
        $rule['callback'] = $callback;
        self::$ruleData[] = $rule;
    }

    /**
     * 添加GET规则
     * @param string|array $url
     * @param array|\Closure $callback
     */
    public static function get($url, $callback) {
        self::setRule('get', $url, $callback);
    }

    /**
     * 添加POST规则
     * @param string|array $url
     * @param array|\Closure $callback
     */
    public static function post($url, $callback) {
        self::setRule('post', $url, $callback);
    }

    /**
     * 添加PUT规则
     * @param string|array $url
     * @param array|\Closure $callback
     */
    public static function put($url, $callback) {
        self::setRule('put', $url, $callback);
    }

    /**
     * 添加DELETE规则
     * @param string|array $url
     * @param array|\Closure $callback
     */
    public static function delete($url, $callback) {
        self::setRule('delete', $url, $callback);
    }

    /**
     * 添加不区分请求的规则
     * @param string|array $url
     * @param array|\Closure $callback
     */
    public static function all($url, $callback) {
        self::setRule('all', $url, $callback);
    }

    //----------------------------

    /**
     * Restful状态
     * @var bool
     */
    private static $isRestful = false;

    /**
     * 设置Restful
     * @param bool $flag
     */
    public static function setRestful($flag) {
        self::$isRestful = (bool)$flag;
    }

    /**
     * 设置忽略后缀名
     * @var bool
     */
    private static $ignoreExt = false;

    /**
     * 设置是否忽略后缀名
     * @param bool $bool
     */
    public static function setIgnoreExt($bool) {
        self::$ignoreExt = (bool)$bool;
    }

    //--------------------------------

    /**
     * 处理请求为路由参数
     */
    private static function initParam() {
        $url = $_SERVER['PATH_INFO'];
        if (!$url) {
            $url = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        }
        $ext = pathinfo($url, PATHINFO_EXTENSION);
        if ($ext) {
            $url = str_replace('.' . $ext, '', $url);
            self::$ext = $ext;
        }
        self::$param = array_values(array_filter(explode('/', $url)));
        #处理Restful情况，判断是否读取自定义头信息中的请求方法
        if (self::$isRestful) {
            $method = isset($_SERVER['HTTP_RESTFUL_METHOD']) ? $_SERVER['HTTP_RESTFUL_METHOD'] :
                $_SERVER['REQUEST_METHOD'];
        } else {
            $method = $_SERVER['REQUEST_METHOD'];
        }
        self::$method = strtoupper($method);
    }

    /**
     * 路由分发
     * @return bool|mixed
     */
    public static function dispatch() {
        self::initParam();
        foreach (self::$ruleData as $rule) {
            #判断参数数量
            if (count($rule['param']) != count(self::$param)) {
                continue;
            }
            #判断后缀名
            if ($rule['ext'] != self::$ext && self::$ignoreExt === false) {
                continue;
            }
            #判断方法
            if ($rule['method'] == 'ALL' || $rule['method'] == self::$method) {
                $argData = array();
                $diff = array_diff(self::$param, $rule['param']);
                $diffArg = array_diff($rule['param'], self::$param);
                foreach ($diffArg as $k => $arg) {
                    #判断是否为全参数
                    if (strpos($arg, ':') !== 0) {
                        continue 2;
                    }
                    $argData[ltrim($arg, ':')] = $diff[$k];
                }
                #补齐Action名称
                if (is_array($rule['callback'])) {
                    #调用Action对象
                    return App::Action(join('->', $rule['callback']), $argData);
                }
                return call_user_func_array($rule['callback'], $argData);
            }
        }
        App::error('路由分发失败', 'ROUTER', 404);
        return false;
    }

}